package rr.ui.slideshows
{
	import flash.display.Sprite;
	
	import flash.utils.Timer;
	
	import flash.geom.Point;
	
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.events.IOErrorEvent;
	
	import rr.core.display.Align;
	
	/**
	 * ...
	 * @author Raeef
	 * @version 1.0
	 */
	public class XMLSlideshowCore extends Sprite
	{
		//------------------------------------------------------------------------------------------------------------------------
		
		private var _data			   :XML						 = null;
		
		private var _bitmapsContainer  :Sprite					 = null;
		
		private var _playing		   :Boolean					 = true;
		private var _bitmapsTransparent:Boolean					 = true;
		
		private var _timer			   :Timer					 = null;
		
		private var _bitmapsClass	   :Class					 = null;
		
		private var _bitmaps		   :Vector.<SlideshowBitmap> = null;
		
		private var _width			   :Number					 = NaN;
		private var _height			   :Number					 = NaN;
		private var _stackedBitmap	   :Number					 = NaN;
		
		private var _flow			   :String					 = null;
		private var _align			   :String					 = null;
		private var _pivot			   :String					 = null;
		private var _bitmapsAdjustType :String					 = null;
		
		private var _numBitmaps		   :uint					 = 0;
		private var _nextBitmap		   :uint					 = 1;
		private var _flowStatus		   :uint					 = 1;
		private var _currentBitmap	   :uint					 = 0;
		private var _previousBitmap	   :uint					 = 0;
		private var _numLoadedBitmaps  :uint					 = 0;
		private var _bitmapsFillColor  :uint					 = 0;
		
		//------------------------------------------------------------------------------------------------------------------------
		
		
		
		
		
		//------------------------------------------------------------------------------------------------------------------------
		
		public function XMLSlideshowCore(data:XML, bitmapsClass:Class = null, flow:String = 'normal', width:Number = NaN, height:Number = NaN, pivot:String = 'top_left', align:String = 'top_left', bitmapsAdjustType:String = 'none', bitmapsTransparent:Boolean = true, bitmapsFillColor:uint = 0):void
		{
			this._data				 = data;
			
			this._bitmapsClass		 = bitmapsClass ? bitmapsClass : SlideshowBitmap;
			
			this._flow				 = flow;
			
			this._width				 = width;
			
			this._height			 = height;
			
			this._pivot				 = pivot;
			
			this._align				 = align;
			
			this._bitmapsAdjustType	 = bitmapsAdjustType;
			
			this._bitmapsTransparent = bitmapsTransparent;
			
			this._bitmapsFillColor	 = bitmapsFillColor;
			
			this._numBitmaps		 = this._data.image.length();
			
			this._bitmaps			 = new Vector.<SlideshowBitmap>();
			
			this._bitmapsContainer	 = new Sprite();
			
			Align.setDisObjAlign(this._bitmapsContainer, this._width, this._height, this._pivot);
			
			this.addChild(this._bitmapsContainer);
			
			this.init();
			
			this.loadBitmap();
		}
		
		//------------------------------------------------------------------------------------------------------------------------
		
		
		
		
		
		//------------------------------------------------------------------------------------------------------------------------
		
		private function loadBitmap():void
		{
			this._bitmaps[this._numLoadedBitmaps]	   = new this._bitmapsClass(null, this._width, this._height, this._bitmapsAdjustType, this._align, this._pivot, this._bitmapsTransparent, this._bitmapsFillColor);
			this._bitmaps[this._numLoadedBitmaps].name = String(this._numLoadedBitmaps);
			this._bitmaps[this._numLoadedBitmaps].addEventListener(IOErrorEvent.IO_ERROR, this.bitmapLoadIOErrorEventHandler);
			this._bitmaps[this._numLoadedBitmaps].addEventListener(Event.INIT			, this.bitmapInitHandler);
			this._bitmaps[this._numLoadedBitmaps].load			  (this._data.image[this._numLoadedBitmaps].@src.toString());
		}
		
		private function bitmapLoadIOErrorEventHandler(event:IOErrorEvent):void
		{
			event.target.removeEventListener(IOErrorEvent.IO_ERROR, this.bitmapLoadIOErrorEventHandler);
			event.target.removeEventListener(Event.INIT			  , this.bitmapInitHandler);
			
			delete this._data.image[this._numLoadedBitmaps];
			
			this._numBitmaps--;
			
			this.loadBitmap();
		}
		
		private function bitmapInitHandler(event:Event):void
		{
			event.target.removeEventListener(IOErrorEvent.IO_ERROR, this.bitmapLoadIOErrorEventHandler);
			event.target.removeEventListener(Event.INIT			  , this.bitmapInitHandler);
			
			if		(!this._numLoadedBitmaps)											this.showBitmap();
			else if (this._numLoadedBitmaps == 1 && !this._flowStatus && this._playing) this.initTimer();
			
			this._numLoadedBitmaps++;
			
			if (this._numLoadedBitmaps < this._numBitmaps) this.loadBitmap();
		}
		
		private function showBitmap():void
		{
			this._bitmapsContainer.addChild(this._bitmaps[this._currentBitmap]);
			
			this._bitmaps[this._currentBitmap].addEventListener(Event.OPEN, this.bitmapTransitionInComplete);
			this._bitmaps[this._currentBitmap].transitionIn();
		}
		
		private function bitmapTransitionInComplete(event:Event):void
		{
			event.target.removeEventListener(Event.OPEN	, this.bitmapTransitionInComplete);
			event.target.addEventListener	(Event.CLOSE, this.bitmapTransitionOutComplete);
			
			this.checkFlowStatus();
			
			if (this._flow == SlideshowFlowTypes.REVERSED && this._bitmapsContainer.numChildren > 1) this._bitmaps[this._previousBitmap].transitionOut();
		}
		
		private function bitmapTransitionOutComplete(event:Event):void
		{
			this._bitmaps[this._previousBitmap].removeEventListener(Event.CLOSE, this.bitmapTransitionOutComplete);
			
			this._bitmapsContainer.removeChild(this._bitmaps[this._previousBitmap]);
			
			this.checkFlowStatus();
			
			if (this._flow == SlideshowFlowTypes.NORMAL) this.showBitmap();
		}
		
		private function initTimer():void
		{
			this._timer = new Timer(Number(this._data.image[this._currentBitmap].@delay.toString()) * 1000, 1);
			this._timer.addEventListener(TimerEvent.TIMER_COMPLETE, this.timerCompleteHandler);
			this._timer.start();
		}
		
		private function clearTimer():void
		{
			if (this._timer)
			{
				if (this._timer.running) this._timer.stop();
				
				this._timer.removeEventListener(TimerEvent.TIMER_COMPLETE, this.timerCompleteHandler);
				this._timer = null;
			}
		}
		
		private function timerCompleteHandler(event:TimerEvent):void
		{
			this.clearTimer();
			
			this.startFlow();
		}
		
		private function startFlow():void
		{
			this._nextBitmap = isNaN(this._stackedBitmap) ? this._nextBitmap : this._stackedBitmap;
			
			this._stackedBitmap = NaN;
			
			this.beforeToggling();
			
			this._previousBitmap = this._currentBitmap;
			this._currentBitmap	 = this._nextBitmap;
			this._nextBitmap	 = (this._currentBitmap + 1) % this._numLoadedBitmaps;
			
			switch(this._flow)
			{
				case SlideshowFlowTypes.CROSS:
					
					this._bitmaps[this._previousBitmap].transitionOut();
					
					this.showBitmap();
					
				break;
				
				case SlideshowFlowTypes.REVERSED:
					
					this.showBitmap();
					
				break;
				
				default:
					
					this._bitmaps[this._previousBitmap].transitionOut();
					
				break;
			}
		}
		
		private function checkFlowStatus():void
		{
			this._flowStatus++;
			
			if (this._flowStatus == 2)
			{
				this._flowStatus = 0;
				
				this.afterToggling();
				
				if (this._numLoadedBitmaps > 1)
				{
					if (!isNaN(this._stackedBitmap))
					{
						if (this._stackedBitmap == this._currentBitmap) this._stackedBitmap = NaN;
						
						this.startFlow();
					}
					else if (this._playing) this.initTimer();
				}
			}
		}
		
		//------------------------------------------------------------------------------------------------------------------------
		
		
		
		
		
		//------------------------------------------------------------------------------------------------------------------------
		
		protected function init():void
		{
			
		}
		
		protected function beforeToggling():void
		{
			
		}
		
		protected function afterToggling():void
		{
			
		}
		
		protected function get data():XML
		{
			return this._data;
		}
		
		protected function get previousBitmap():SlideshowBitmap
		{
			return this._numLoadedBitmaps > 1 ? this._bitmaps[this._previousBitmap] : null;
		}
		
		protected function get currentBitmap():SlideshowBitmap
		{
			return this._numLoadedBitmaps ? this._bitmaps[this._currentBitmap] : null;
		}
		
		protected function get nextBitmap():SlideshowBitmap
		{
			return this._numLoadedBitmaps > 1 ? this._bitmaps[this._nextBitmap] : null;
		}
		
		//------------------------------------------------------------------------------------------------------------------------
		
		
		
		
		
		//------------------------------------------------------------------------------------------------------------------------
		
		public function goto(id:uint):void
		{
			this._stackedBitmap = id < this._numLoadedBitmaps ? id : NaN;
			
			if (!this._flowStatus && id != this._currentBitmap && !isNaN(this._stackedBitmap))
			{
				if (this._playing) this.clearTimer();
				
				this.startFlow();
			}
		}
		
		public function stop():void
		{
			this.clearTimer();
			
			this._playing = false;
		}
		
		public function play():void
		{
			if (!this._flowStatus) this.initTimer();
			
			this._playing = true;
		}
		
		//------------------------------------------------------------------------------------------------------------------------
		
		
		
		
		
		//------------------------------------------------------------------------------------------------------------------------
		
		public function kill():void
		{
			this.clearTimer();
			
			for (var i:uint = 0; i < this._numLoadedBitmaps; i++) this._bitmaps[i].kill();
		}
		
		//------------------------------------------------------------------------------------------------------------------------
	}
}